home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / text / hyper / hsc_source.lha / source / hscdepp / hscdepp.c < prev   
C/C++ Source or Header  |  1996-09-09  |  19KB  |  744 lines

  1. /*
  2.  * hscdepp
  3.  *
  4.  * Dependency generator for hsc-project
  5.  *
  6.  * Copyright (C) 1996  Thomas Aglassinger
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  *-------------------------------------------------------------------
  23.  *
  24.  * Author : Thomas Aglassinger (Tommy-Saftwörx)
  25.  * Email  : agi@giga.or.at, agi@sbox.tu-graz.ac.at
  26.  * Address: Lissagasse 12/II/9
  27.  *          8020 Graz
  28.  *          AUSTRIA
  29.  *
  30.  *-------------------------------------------------------------------
  31.  *
  32.  * hscdepp/hscdepp.c
  33.  *
  34.  * updated:  8-Sep-1996
  35.  * created:  8-Jul-1996
  36.  */
  37.  
  38. /* ANSI includes */
  39. #include <stdio.h>
  40. #include <errno.h>
  41. #include <string.h>
  42. #include <time.h>
  43.  
  44. /* ugly includes */
  45. #include "ugly/ustring.h"
  46. #include "ugly/dllist.h"
  47. #include "ugly/expstr.h"
  48. #include "ugly/infile.h"
  49. #include "ugly/uargs.h"
  50. #include "ugly/prginfo.h"
  51. #include "ugly/returncd.h"
  52.  
  53. /* hsclib includes */
  54. #include "hscprj/document.h"
  55. #include "hscprj/project.h"
  56.  
  57. /* include revision data */
  58. #include "hscdepp/hscdepp_rev.h"
  59.  
  60. #ifdef AMIGA
  61. /* AmigaOS version string
  62.  * (imported from "hscdepp_rev.h")
  63.  */
  64. static const STRPTR AmigaOS_version = VERSTAG;
  65. #endif
  66.  
  67. /* prefix for messages */
  68. #define HD ""
  69. #define DHD "*hscdep* "
  70. #define SHIT "*** "             /* prefix for total failure */
  71.  
  72. /* debugging define */
  73. #ifdef DEBUG
  74. #undef DEBUG
  75. #define DEBUG 1
  76. #endif
  77.  
  78. #ifdef D
  79. #undef D
  80. #endif
  81.  
  82. #if DEBUG
  83. #define D(x) if (debug) {x;}
  84. #else
  85. #define D(x) {/*nufin*/}
  86. #endif
  87.  
  88. /* step-sizes for input-file/depency-string */
  89. #define CHUNKSIZE_INPUTFILE (64*1024)
  90. #define CHUNKSIZE_DEPENDSTR (16*1024)
  91.  
  92. /* default parameters */
  93. #define DEFAULT_PROJECT "hsc.project"   /* project-filename */
  94. #define DEFAULT_NAMEALL "all_hsc"       /* "all"-rule */
  95.  
  96. /* size of buffer for fgets() */
  97. #define MAXBUFSIZE 1024
  98.  
  99. #define STR_DEPENDS_PRECEDE \
  100.     "# --- DO NOT MODIFY THIS LINE -- hsc-dependencies precede ---\n"
  101. #define STR_DEPENDS_FOLLOW \
  102.     "# --- DO NOT MODIFY THIS LINE -- hsc-dependencies follow ---\n"
  103.  
  104. /*
  105.  * global vars
  106.  */
  107. static int return_code = RC_FAIL;       /* exit code of program */
  108.  
  109. static STRPTR makefile = NULL;
  110. static STRPTR prjfile = NULL;
  111. static STRPTR nameall = NULL;
  112. static BOOL verbose = FALSE;
  113. static BOOL nobackup = FALSE;
  114. static BOOL notaglines = FALSE;
  115. static BOOL debug = FALSE;
  116.  
  117. static EXPSTR *lines_precede = NULL;
  118. static EXPSTR *lines_follow = NULL;
  119. static EXPSTR *lines_depend = NULL;
  120.  
  121. static HSCPRJ *project = NULL;
  122.  
  123. /*
  124.  * cleanup: free all resources
  125.  * (called in any case)
  126.  */
  127. static VOID cleanup(VOID)
  128. {
  129.     D(fprintf(stderr, "(cleanup)\r"));
  130.     del_project(project);
  131.     del_estr(lines_precede);
  132.     del_estr(lines_follow);
  133.     del_estr(lines_depend);
  134.     D(fprintf(stderr, "         "));
  135. }
  136.  
  137. static VOID set_return_code(int new_code)
  138. {
  139.     if (new_code > return_code)
  140.         return_code = new_code;
  141. }
  142.  
  143. /*
  144.  * hsc_nomem_handler
  145.  *
  146.  * called from ugly/umalloc, if malloc() did return NULL
  147.  */
  148. static BOOL hscdepp_nomem_handler(size_t size)
  149. {
  150.     fputs(SHIT "out of memory\n", stderr);
  151.  
  152.     return_code = RC_FAIL;
  153.  
  154.     exit(return_code);
  155.  
  156.     return (FALSE);             /* immediatly abort */
  157. }
  158.  
  159. VOID msg_corrupt_pf(HSCPRJ * hp, STRPTR reason)
  160. {
  161.     fprintf(stderr, "project-file corrupt: %s\n", reason);
  162. }
  163.  
  164. /*
  165.  * show_license
  166.  *
  167.  * display short description of GNU GPL
  168.  */
  169. static VOID show_license(VOID)
  170. {
  171.     STRPTR license =            /* the usual boring text */
  172.     "\nThis program is free software; you can redistribute it and/or modify\n"
  173.     "it under the terms of the GNU General Public License as published by\n"
  174.     "the Free Software Foundation; either version 2 of the License, or\n"
  175.     "(at your option) any later version.\n\n"
  176.  
  177.     "This program is distributed in the hope that it will be useful,\n"
  178.     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  179.     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
  180.     "GNU General Public License for more details.\n\n"
  181.  
  182.     "You should have received a copy of the GNU General Public License\n"
  183.     "along with this program; if not, write to the Free Software\n"
  184.     "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n";
  185.  
  186.     fprintf(stderr, license);
  187. }
  188.  
  189. /*
  190.  * args_ok
  191.  *
  192.  * prepare args, check & parse user args, display error and
  193.  * help message if neccessary
  194.  *
  195.  * result: TRUE, if all args ok and no request for HELP or
  196.  *         LICENSE has been detected
  197.  */
  198. static BOOL args_ok(int argc, char *argv[])
  199. {
  200.     struct arglist *hscdepp_args;       /* argument structure */
  201.     BOOL arg_help = FALSE;
  202.     BOOL arg_license = FALSE;
  203.     BOOL ok = FALSE;
  204.  
  205.     /* create arg-table */
  206.     hscdepp_args = prepare_args
  207.         ("HSCDEPP_ARGS",
  208.          "FILE/T", &makefile, "makefile to update",
  209.          "PRJFILE/T/K", &prjfile, "project file",
  210.          "NAMEALL/T/K", &nameall, "name for `all_hsc' rule",
  211.          "VERBOSE/S", &verbose, "verbose output",
  212.          "NOBACKUP/S", &nobackup, "do not backup makefile",
  213.          "NOTAGLINES/S", ¬aglines, "do not write taglines",
  214.          "-DEBUG/S", &debug, "enable debugging output",
  215.          "HELP=?=-h/S", &arg_help, "display this text",
  216.          "LICENSE/S", &arg_license, "display license",
  217.          NULL);
  218.  
  219.     ok = (hscdepp_args != NULL);
  220.  
  221.     /* set & test args */
  222.     if (ok)
  223.     {
  224.         ok = set_args(argc, argv, hscdepp_args);
  225.  
  226.         /* display argument error message */
  227.         if (!ok)
  228.         {
  229.             pargerr();
  230.             set_return_code(RC_ERROR);
  231.         }
  232.         else if (arg_help || arg_license)
  233.         {
  234.             /*
  235.              * display help or license text
  236.              */
  237.             fprintf_prginfo(stderr);
  238.             if (arg_help)
  239.                 fprintf_arghelp(stderr, hscdepp_args);
  240.             else
  241.                 show_license();
  242.             set_return_code(RC_WARN);
  243.             ok = FALSE;
  244.         }
  245.         else
  246.         {
  247.             /* auto-enable verbose in debug-mode */
  248.             if (debug)
  249.                 verbose = TRUE;
  250.  
  251.             /* display copyright in verbose-mode */
  252.             if (verbose)
  253.                 fprintf_prginfo(stderr);
  254.  
  255.             /* set default-parameters if neccessary */
  256.             if (!prjfile)
  257.             {
  258.                 prjfile = DEFAULT_PROJECT;
  259.                 if (verbose)
  260.                     fprintf(stderr, HD "%s: using default project-file\n",
  261.                             prjfile);
  262.             }
  263.             if (!nameall)
  264.             {
  265.                 nameall = DEFAULT_NAMEALL;
  266.  
  267.             }
  268.  
  269.             /* debugging control output */
  270.             D(
  271.                  if (makefile)
  272.                  {
  273.                  fprintf(stderr, DHD "makefile=`%s'\n", makefile);
  274.                  fprintf(stderr, DHD "makefile=DEFAULT\n");
  275.                  fprintf(stderr, DHD "prjfile =`%s'\n", prjfile);
  276.                  fprintf(stderr, DHD "nameall =`%s'\n", nameall);
  277.                  }
  278.             );
  279.         }
  280.  
  281.         /* release mem used by args */
  282.         free_args(hscdepp_args);
  283.     }
  284.     else
  285.     {
  286.         /* only for developer */
  287.         D(fprintf(stderr, SHIT "ArgDef error: %lu\n", prep_error_num));
  288.     }
  289.  
  290. #if 1
  291.     return (ok);
  292. #else
  293.     return (FALSE);             /* for arg-debugging */
  294. #endif
  295. }
  296.  
  297. /*
  298.  * read_makefile
  299.  *
  300.  * scan for fitting makefile, read all it's data into a list
  301.  * of strings, exept those which are between taglines
  302.  */
  303. static BOOL read_makefile(VOID)
  304. {
  305.     STRPTR scanfile[] =
  306.     {"GNUmakefile", "Makefile", "makefile", NULL};
  307.     FILE *file = NULL;
  308.     BOOL ok = FALSE;
  309.  
  310.     lines_precede = init_estr(1024);
  311.     lines_follow = init_estr(1024);
  312.  
  313.     /*
  314.      * open makefile
  315.      */
  316.     errno = 0;
  317.     if (!makefile)
  318.     {
  319.         /* scan for makefile */
  320.         int i = 0;
  321.  
  322.         D(fprintf(stderr, DHD "scanning makefile\n"));
  323.         makefile = scanfile[0];
  324.         while (!file && makefile)
  325.         {
  326.             D(fprintf(stderr, DHD "  try `%s'\n", makefile));
  327.             file = fopen(makefile, "r");
  328.             if (!file)
  329.             {
  330.                 i += 1;
  331.                 makefile = scanfile[i];
  332.             }
  333.         }
  334.  
  335.     }
  336.     else
  337.     {
  338.         /* use makefile specified by user */
  339.         D(fprintf(stderr, DHD "makefile `%s' specified by user\n", makefile));
  340.         file = fopen(makefile, "r");
  341.     }
  342.  
  343.     if (!file)
  344.     {
  345.         if (!makefile)
  346.             makefile = "Makefile";
  347.         fprintf(stderr, HD "%s: creating new makefile\n", makefile);
  348.         ok = TRUE;
  349.     }
  350.     else
  351.     {
  352.         static STRARR buf[MAXBUFSIZE];  /* buffer for fgets() */
  353.         BOOL found = FALSE;     /* flag: tag-line found */
  354.         STRPTR line = NULL;     /* current line read */
  355.  
  356.         /*
  357.          * read Makefile
  358.          */
  359.  
  360.         /* reset error variable */
  361.         errno = 0;
  362.  
  363.         /*
  364.          * read preceding lines
  365.          */
  366.         do
  367.         {
  368.             line = fgets(buf, MAXBUFSIZE, file);
  369.             if (line)
  370.                 if (!strcmp(line, STR_DEPENDS_FOLLOW))
  371.                     found = TRUE;
  372.                 else
  373.                     app_estr(lines_precede, line);
  374.         }
  375.         while (!found && !errno && line);
  376.  
  377.         if (errno)
  378.         {
  379.             fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  380.             set_return_code(RC_ERROR);
  381.         }
  382.         else if (!line)
  383.         {
  384.             /* tag-line not found */
  385.             if (verbose)
  386.                 fprintf(stderr, HD "%s: no starting tag-line; "
  387.                         "appending dependencies\n", makefile);
  388.         }
  389.         else
  390.         {
  391.             /*
  392.              * skip old dependencies
  393.              */
  394.             D(fprintf(stderr, DHD "starting tagline found\n"));
  395.  
  396.             found = FALSE;
  397.             do
  398.             {
  399.                 line = fgets(buf, MAXBUFSIZE, file);
  400.                 if (line)
  401.                     if (!strcmp(line, STR_DEPENDS_PRECEDE))
  402.                         found = TRUE;
  403.             }
  404.             while (!found && !errno && line);
  405.  
  406.             if (errno)
  407.             {
  408.                 fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  409.                 set_return_code(RC_ERROR);
  410.             }
  411.             else if (!line)
  412.             {
  413.                 /* tag-line not found */
  414.                 if (verbose)
  415.                     fprintf(stderr, HD "%s: no ending tag-line; "
  416.                             "appending dependencies\n", makefile);
  417.             }
  418.             else
  419.             {
  420.                 /*
  421.                  * read following lines
  422.                  */
  423.                 D(fprintf(stderr, DHD "ending tagline found\n"));
  424.                 do
  425.                 {
  426.                     line = fgets(buf, MAXBUFSIZE, file);
  427.                     if (line)
  428.                         app_estr(lines_follow, line);
  429.                 }
  430.                 while (!errno && line);
  431.  
  432.                 if (errno)
  433.                 {
  434.                     fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  435.                     set_return_code(RC_ERROR);
  436.                 }
  437.             }
  438.         }
  439.  
  440.         if (!errno)
  441.         {
  442.             if (verbose)
  443.                 fprintf(stderr, HD "%s: makefile read\n", makefile);
  444.             ok = TRUE;
  445.         }
  446.         /* close makefile */
  447.         fclose(file);
  448.     }
  449.  
  450.     return (ok);
  451. }
  452.  
  453. /*
  454.  * read_project
  455.  *
  456.  * read data from project file
  457.  */
  458. static BOOL read_project(VOID)
  459. {
  460.     BOOL ok = FALSE;
  461.     INFILE *inpf = NULL;
  462.  
  463.     if (verbose)
  464.     {
  465.         fprintf(stderr, HD "%s: reading..\r", prjfile);
  466.         fflush(stderr);
  467.     }
  468.  
  469.     /* assign message-callback for corrupt project-file */
  470.     project->CB_msg_corrupt_pf = msg_corrupt_pf;
  471.  
  472.     /* read project-file */
  473.     errno = 0;
  474.     inpf = infopen(prjfile, CHUNKSIZE_INPUTFILE);
  475.     if (inpf)
  476.     {
  477.         if (hsc_project_read_file(project, inpf))
  478.         {
  479.             if (verbose)
  480.                 fprintf(stderr, HD "%s: project-file read\n", prjfile);
  481.             ok = TRUE;
  482.         }
  483.         infclose(inpf);
  484.     }
  485.  
  486.     if (!ok)
  487.     {
  488.         fprintf(stderr, HD "error reading `%s'", prjfile);
  489.         if (errno)
  490.             fprintf(stderr, HD ": %s", strerror(errno));
  491.         fprintf(stderr, "\n");
  492.     }
  493.  
  494.     return (ok);
  495. }
  496.  
  497. /*
  498.  * update_makefile
  499.  *
  500.  * create dependency-lines from project-info,
  501.  */
  502.  
  503. /* append linefeed to dependency-line */
  504. static VOID depline_applf(ULONG * linelen)
  505. {
  506.     *linelen = 0;
  507.     app_estr(lines_depend, "\n");
  508. }
  509.  
  510. /* append string to dependency-line */
  511. static VOID depline_appstr(STRPTR s, ULONG * linelen)
  512. {
  513. #define LEADING_BLANKS "   "
  514.     size_t slen = strlen(s);
  515.  
  516.     /* check if line would become too long after appending
  517.      * the current word */
  518.     if ((*linelen + slen) >= 75)
  519.     {
  520.         D(fprintf(stderr, DHD "break line after %lu chars to avoid %lu\n",
  521.                   *linelen, *linelen + slen));
  522.  
  523.         app_estr(lines_depend, " \\\n");
  524.         app_estr(lines_depend, LEADING_BLANKS);
  525.         *linelen = strlen(LEADING_BLANKS);
  526.     }
  527.  
  528.     app_estrch(lines_depend, ' ');
  529.     app_estr(lines_depend, s);
  530.     *linelen = *linelen + slen + 1;
  531. }
  532.  
  533. /*
  534.  * update_makefile - main function
  535.  */
  536. static BOOL update_makefile(VOID)
  537. {
  538.     BOOL ok = FALSE;
  539.     ULONG linelen = 0;          /* length of current line */
  540.     DLNODE *docnode = dll_first(project->documents);
  541.     BOOL bak_ok = TRUE;
  542.  
  543.     lines_depend = init_estr(CHUNKSIZE_DEPENDSTR);
  544.  
  545.     /* append tagline */
  546.     if (!notaglines)
  547.         app_estr(lines_depend, STR_DEPENDS_FOLLOW);
  548.  
  549.     /* append some header info */
  550.     if (!notaglines)
  551.     {
  552. #define MAXTIMEBUF 40
  553.         time_t now = time(NULL);
  554.         STRARR timebuf[MAXTIMEBUF];
  555.  
  556.         if (strftime(timebuf, MAXTIMEBUF, "%A %d-%b-%Y %H:%M:%S",
  557.                      localtime(&now)))
  558.         {
  559.             app_estr(lines_depend, "\n# dependencies updated: ");
  560.             app_estr(lines_depend, timebuf);
  561.             app_estr(lines_depend, "\n\n");
  562.         }
  563.     }
  564.  
  565.     /*
  566.      * append all-rule
  567.      */
  568.     if (docnode->data)
  569.     {
  570.         app_estr(lines_depend, nameall);
  571.         app_estr(lines_depend, " :");
  572.         linelen = strlen(nameall) + 2;
  573.  
  574.         while (docnode)
  575.         {
  576.             HSCDOC *document = dln_data(docnode);
  577.             depline_appstr(document->docname, &linelen);
  578.  
  579.             docnode = dln_next(docnode);
  580.         }
  581.         app_estr(lines_depend, "\n\n");
  582.     }
  583.  
  584.     /*
  585.      * append document data
  586.      */
  587.     docnode = dll_first(project->documents);
  588.     while (docnode)
  589.     {
  590.         HSCDOC *document = dln_data(docnode);
  591.         DLNODE *incnode = dll_first(document->includes);
  592.  
  593.         D(fprintf(stderr, DHD "document `%s'\n", document->docname));
  594.  
  595.         app_estr(lines_depend, document->docname);
  596.         app_estr(lines_depend, " :");
  597.  
  598.         linelen = strlen(document->docname) + 2;
  599.  
  600.         /* dependency for main source */
  601.         depline_appstr(document->sourcename, &linelen);
  602.  
  603.         /* dependencies for includes */
  604.         while (incnode)
  605.         {
  606.             HSCINC *include = dln_data(incnode);
  607.             depline_appstr(include->name, &linelen);
  608.  
  609.             incnode = dln_next(incnode);
  610.         }
  611.  
  612.         /* append linefeed after dependency-list */
  613.         app_estr(lines_depend, "\n\n");
  614.  
  615.         docnode = dln_next(docnode);
  616.     }
  617.  
  618.     /* append tagline */
  619.     if (!notaglines)
  620.         app_estr(lines_depend, STR_DEPENDS_PRECEDE);
  621.  
  622.     /*
  623.      * create backup
  624.      */
  625.     if (!nobackup)
  626.     {
  627.         EXPSTR *makefile_bak = init_estr(32);   /* filename for backup */
  628.  
  629.         set_estr(makefile_bak, makefile);
  630.         app_estr(makefile_bak, ".bak");
  631.  
  632.         /* remove old backup */
  633.         remove(estr2str(makefile_bak));
  634.  
  635.         /* rename old makefile to backup
  636.          *
  637.          * NOTE: if this fails, this can also be because
  638.          * there wasn't any earlier copy, therefor no
  639.          * error-message is displayed */
  640.         if (!rename(makefile, estr2str(makefile_bak)))
  641.         {
  642.             if (verbose)
  643.                 fprintf(stderr, HD "%s: backup created\n",
  644.                         estr2str(makefile_bak));
  645.         }
  646.  
  647.         del_estr(makefile_bak);
  648.     }
  649.  
  650.     /*
  651.      * write makefile
  652.      */
  653.     if (bak_ok)
  654.     {
  655.         FILE *outf = NULL;
  656.  
  657.         /* open output makefile */
  658.         errno = 0;
  659.         outf = fopen(makefile, "w");
  660.         if (outf)
  661.         {
  662.             /* write output */
  663.             errno = 0;
  664.             fprintf(outf, "%s%s%s",
  665.                     estr2str(lines_precede), estr2str(lines_depend),
  666.                     estr2str(lines_follow));
  667.  
  668.             if (errno)
  669.             {
  670.                 /* write error */
  671.                 fprintf(stderr, "error writing to `%s': %s\n",
  672.                         makefile, strerror(errno));
  673.             }
  674.             else
  675.                 ok = TRUE;
  676.  
  677.             /* close output */
  678.             fclose(outf);
  679.         }
  680.         else
  681.         {
  682.             /* error opening output */
  683.             fprintf(stderr, "error opening `%s' for output: %s\n",
  684.                     makefile, strerror(errno));
  685.         }
  686.     }
  687.  
  688.     return (ok);
  689. }
  690.  
  691. /*
  692.  *
  693.  * main function
  694.  *
  695.  */
  696. int main(int argc, char *argv[])
  697. {
  698. #ifndef BETA
  699. #define BETA 0
  700. #endif
  701.     /* set program information */
  702.     set_prginfo("hscdepp", "Tommy-Saftwörx", VERSION, REVISION, BETA,
  703.                 "hsc dependency procreator",
  704.                 "Freeware, type `hscdepp LICENSE' for details.");
  705.  
  706. #if DEBUG
  707.     /* display a memory tracking report */
  708.     /* at end of execution */
  709.     atexit(atexit_uglymemory);
  710. #endif
  711.  
  712.     /* install nomem-handler */
  713.     ugly_nomem_handler = hscdepp_nomem_handler;
  714.  
  715.     /* use cleanup() as additional exit func */
  716.     if (!atexit(cleanup))
  717.     {
  718.         /*
  719.          * main procedure
  720.          */
  721.         return_code = RC_OK;
  722.         project = new_project();
  723.         if (project
  724.             && args_ok(argc, argv)
  725.             && read_makefile()
  726.             && read_project()
  727.             && update_makefile()
  728.         )
  729.         {
  730.             if (verbose)
  731.             {
  732.                 fprintf(stderr, HD "%s: updated using `%s'\n",
  733.                         makefile, prjfile);
  734.             }
  735.             return_code = RC_OK;
  736.         }
  737.     }
  738.     else
  739.     {
  740.         fputs(SHIT "atexit() failed ", stderr);
  741.     }
  742.     return (return_code);
  743. }
  744.